package net.loodies;




import java.util.ArrayList;
import java.util.Hashtable;

import android.util.Log;

/* 
 * Finite State Machine Class
 * 
 */
 public  class FSM {

	 private static final boolean DEBUG = false;
	 protected static final String TAG = "FSM";
		
	 public boolean FSMfinishPlease = false;
	 float alpha = 0;
	 int2 position = new int2(0,0);
	public FSM()
	{
	
		arrayStates = new ArrayList<State>();
	
	}
	public int2 getPosition2D(){
		return position;
	}
	interface IState
	{
		public void DoUpdate(float deltaTime);
		public void DoEnter();
		public void DoExit();
	};

	
	public abstract class State implements IState
	{
		FSM fsm;
		String name;
		
		Hashtable<String, String> map;
		public State(FSM _fsm,String _name) {
			fsm =_fsm;
			name=_name;
		}
	
	}

	State currentState;
	State goToState;
	public ArrayList<State> arrayStates;
	
	public void Add(State _state)
	{
		if(_state!=null)
		{
			arrayStates.add(_state);
		}
	}
	public void Update(float deltaTime) 
	{
		if(currentState!=null)
		{
			currentState.DoUpdate(deltaTime);
		}
	}
	public void Start(){
		if(arrayStates!=null && arrayStates.size() >0){
			ChangeState(arrayStates.get(0).name);
		}
		
	}
	public void Stop(){
		currentState=null;
		goToState = null;
		
	}
	public String getCurrentStateName(){
		return currentState.name;
	}
	public void ChangeState(String _stateName) 
	{
		if (DEBUG) {
			Log.v(TAG, "ChangeState" + _stateName);
		}
		
		goToState = null;
		for (int i = 0 ; i< arrayStates.size();i++)
		{
			if(arrayStates.get(i).name ==_stateName)
			{
				goToState=arrayStates.get(i);
			}
		}
		if(currentState!=null )
		{
			currentState.DoExit();

		}
		if(goToState!=null)
		{
			currentState = goToState;
			goToState.DoEnter();
		}
		
	}
	
	
	public class StateIDLE extends State 
	{
		long targetTime;
		public  String name = "StateIDLE";
		public  long duration = 5000;
		
		public StateIDLE(FSM _fsm,String _name,int _duration) {
			super(_fsm,_name);
			
		}	
		public void DoUpdate(float deltaTime)
		{
			long current =  System.currentTimeMillis();
			long left = targetTime-current;
			if(left<0 && ( duration!= -1))
			{
				fsm.ChangeState("StateFADEOUT");
			}
		}
		public void DoEnter()
		{
			targetTime=System.currentTimeMillis()+duration;
		
			if (DEBUG) {
				Log.v(TAG, "StateIDLE::DoEnter");
				System.out.println("StateIDLE::DoEnter");
			}
			
		}
		public void DoExit()
		{
			if (DEBUG) {
				Log.v(TAG, "StateIDLE::DoExit");
			}
			
		}
	}
	public class StateWAITFORFADEOUT extends State 
	{
		long targetTime;
		public  String name = "StateWAITFORFADEOUT";
		public  long duration = 5000;
		
		public StateWAITFORFADEOUT(FSM _fsm,String _name,int _duration) {
			super(_fsm,_name);
			
		}	
		public void DoUpdate(float deltaTime)
		{
			long current =  System.currentTimeMillis();
			long left = targetTime-current;
			if(left<0 )
			{
				
			}
		}
		public void DoEnter()
		{
			targetTime=System.currentTimeMillis()+duration;
			if (DEBUG) {
				Log.v(TAG, "StateWAITFORFADEOUT::DoEnter");
			}
			
			
		}
		public void DoExit()
		{
			if (DEBUG) {
				Log.v(TAG, "StateWAITFORFADEOUT::DoExit");
			}
		}
	}
	public class StateFADEOUT extends State 
	{
		long targetTime;
		public  String name = "StateFADEOUT";
		public  long duration = 2000;
		
		public StateFADEOUT(FSM _fsm,String _name,int _duration) {
			super(_fsm,_name);
			duration =  _duration;
			
		}	
			
		public void DoUpdate(float deltaTime)
		{
			long current =  System.currentTimeMillis();
			long left = targetTime-current;
			if(left<0)
			{
				alpha= 0 ;
				FSMfinishPlease = true;
				return;
			}
			float falpha = ((float)left*((float)256/duration));
			alpha= (int)(falpha) ;
			if (DEBUG) {
				Log.v(TAG, "StateFADEOUT::left");
			}
			if (DEBUG) {
				Log.v(TAG, Integer.toString((int) left));
			}
			
			
		
		}
		public void DoEnter()
		{
			targetTime=System.currentTimeMillis()+duration;
			if (DEBUG) {
				Log.v(TAG, "StateFADEOUT:DoEnter");
			}
			
		}
		public void DoExit()
		{
			alpha= 0;
			if (DEBUG) {
				Log.v(TAG, "StateFADEOUT:DoExit");
			}
			
		}
	}
	public class StateFADEIN extends State 
	{
		long targetTime;
		public  String name = "";
		public  long duration = 2000;
		public StateFADEIN(FSM _fsm,String _name,int _duration) {
			super(_fsm,_name);
			duration =  _duration;
		}	
			
		public void DoUpdate(float deltaTime)
		{
			
			long current =  System.currentTimeMillis();
			long left = targetTime-current;
			if(left<0)
			{
				fsm.ChangeState("StateIDLE");
			}
			else
			{
				float falpha = ((float)left*((float)256/duration));
				alpha= (int)(255.0f - falpha) ;
				if (DEBUG) {
					Log.e(TAG, "StateFADEIN::left");
					Log.e(TAG, Integer.toString((int) left));
				}
				
				
			}
			
		}
		public void DoEnter()
		{
			targetTime=System.currentTimeMillis()+duration;
			alpha=0;
			if (DEBUG) {
						//System.out.println("StateFADEIN::DoEnter");
						
			}
		}
		public void DoExit()
		{
			alpha= 255;
			
			if (DEBUG) {
				//System.out.println("StateFADEIN::DoExit");
			}
		}
	}
	public class StateFADEIN_TOWAIT extends State 
	{
		long targetTime;
		public  String name = "";
		public  long duration = 2000;
		public StateFADEIN_TOWAIT(FSM _fsm,String _name,int _duration) {
			super(_fsm,_name);
			duration =  _duration;
		}	
	
		
		public void DoEnter()
		{
			targetTime=System.currentTimeMillis()+duration;
			alpha=0;
			if (DEBUG) {
						//System.out.println("StateFADEIN_TOWAIT::DoEnter");
						
			}
		}
		public void DoUpdate(float deltaTime)
		{
			
			long current =  System.currentTimeMillis();
			long left = targetTime-current;
			if(left<0)
			{
				fsm.ChangeState("StateWAITFORFADEOUT");
			}
			else
			{
				float falpha = ((float)left*((float)256/duration));
				alpha= (int)(255.0f - falpha) ;
				
			}
			
		}
		public void DoExit()
		{
			alpha= 255;
			
			if (DEBUG) {
				//System.out.println("StateFADEIN_TOWAIT::DoExit");
			}
		}
	}
	public class StateBANNERUP extends State 
	{
		public long targetTime;
		public int2 targetLocation;

		public long duration;
		public float2 currentPos;
		float startPosx ;
		float startPosy ;
		float2 startPos;
		int startPosIntx;
		int startPosInty;
		public String nextState;
		float2 totalDistance = new float2(0,0);
	
		public StateBANNERUP(FSM _fsm,int _duration,int2 loc,int2 curpos,String next ) {
			
			super(_fsm,"StateBANNERUP");
			duration =  _duration;
			targetLocation = loc;
			currentPos = new float2(0,0);
			currentPos.x = (float)curpos.x;
			currentPos.y = (float)curpos.y;
			startPosIntx = curpos.x;
			startPosInty = curpos.y;
			startPosx = (float)curpos.x;
			startPosy = (float)curpos.y;
			startPos   = new float2(startPosx,startPosy);
			
			if (DEBUG) {
				Log.v(TAG,name + "CTOR :startPos:"+ startPos.x+ " " + startPos.y)  ;
			}
			nextState = next;
			totalDistance.x = (float)targetLocation.x - currentPos.x;
			totalDistance.y = (float)targetLocation.y - currentPos.y;
		}	
		public void NextState(){
			if (DEBUG) {
				Log.v(TAG,name + ":NextState():"+ "StateBANNER_IDLE_IN_UP")  ;
			}
			fsm.ChangeState("StateBANNER_IDLE_IN_UP");
		
			
		}
		public void DoEnter()
		{
			targetTime=System.currentTimeMillis()+duration;
			currentPos = startPos;
			currentPos.x = (float)startPosIntx;
			currentPos.y = (float)startPosInty;
			
	//		Log.v(TAG,name + "DoEnter :startPos:"+ startPos.x+ " " + startPos.y +"__ itn:"+ startPosIntx+" " + startPosInty)  ;
				
	//		Log.v(TAG,name + "::DoEnter()"+"duration: " + duration +" target = " + targetLocation.x +" "+targetLocation.y +":currentPos" + currentPos.x + " "+currentPos.y + "startPos:" + startPos.x+" "+startPos.y )  ;
			
		}
		public void DoUpdate(float deltaTime)
		{
			long current =  System.currentTimeMillis();
			@SuppressWarnings("unused")
			long left 	 =  targetTime-current;
			float incperframe = duration / deltaTime; 
			float incDistancex = totalDistance.x / incperframe;
			float incDistancey = totalDistance.y / incperframe;
			
			currentPos.x += incDistancex;
			currentPos.y += incDistancey;

//			if(name!="StateBANNERIDLE"){
//				Log.v(TAG,name + "timeleft: " + left +" target = " + targetLocation.x +" "+targetLocation.y +":currentPos" + currentPos.x + " "+currentPos.y )  ;
//					
//			}
//			
			position.x = (int)currentPos.x;
			position.y = (int)currentPos.y;
			if(current>=targetTime){
				NextState();
				position.x = (int)targetLocation.x;
				position.y = (int)targetLocation.y;
			}
		}
		public void DoExit()
		{
			if (DEBUG) {
				Log.v(TAG,name+"::DoExit()");
			}
			
		}
	}
	public class StateBANNER_IDLE_IN_UP extends StateBANNERUP 
	{
		
		public StateBANNER_IDLE_IN_UP(FSM fsm,  int duration, int2 loc,
				int2 curpos, String next) {
			super(fsm,  duration, loc, curpos, next);
			name = "StateBANNER_IDLE_IN_UP";
			// TODO Auto-generated constructor stub
		}
		public void NextState(){
			if (DEBUG) {
				Log.v(TAG,name + ":NextState():"+ "StateBANNERDOWN")  ;
			}
			fsm.ChangeState("StateBANNERDOWN");
			
		}
	}
	public class StateBANNER_IDLE_IN_DOWN extends StateBANNERUP 
	{

		public StateBANNER_IDLE_IN_DOWN(FSM fsm, int duration, int2 loc,
				int2 curpos, String next) {
			super(fsm,  duration, loc, curpos, next);
			// TODO Auto-generated constructor stub
			name = "StateBANNER_IDLE_IN_DOWN";
		}
		public void NextState(){
			if (DEBUG) {
				Log.v(TAG,name + ":NextState():"+ "StateBANNER_IDLE_IN_DOWN")  ;
			}
			fsm.ChangeState("StateBANNER_IDLE_IN_DOWN");
			
		}
	}
	public class StateBANNERDOWN extends StateBANNERUP 
	{

		public StateBANNERDOWN(FSM fsm,  int duration, int2 loc,
				int2 curpos, String next) {
			super(fsm, duration, loc, curpos, next);
			name = "StateBANNERDOWN";
	
		}
		public void NextState(){
			if (DEBUG) {
				Log.v(TAG,name + ":NextState():"+ "StateBANNER_IDLE_IN_DOWN")  ;
			}
				fsm.ChangeState("StateBANNER_IDLE_IN_DOWN");
			
		}
	}
	public class StateBANNER_IDLE_IN_START extends StateBANNERUP 
	{

		public StateBANNER_IDLE_IN_START(FSM fsm,  int duration, int2 loc,
				int2 curpos, String next) {
			super(fsm, duration, loc, curpos, next);
			name = "StateBANNER_IDLE_IN_START";
	
		}
		public void NextState(){
			if (DEBUG) {
				Log.v(TAG,name + ":NextState():"+ "StateBANNERUP")  ;
			}
				fsm.ChangeState("StateBANNERUP");
			
		}
	}
	
}
